package com.suppor.rpc.proto.handler;

import com.google.gson.Gson;
import com.suppor.rpc.core.trans.RpcRequest;
import com.suppor.rpc.core.trans.RpcResponse;
import com.suppor.rpc.core.util.RpcServiceUtil;
import com.suppor.rpc.proto.protocol.MsgHeader;
import com.suppor.rpc.proto.protocol.MsgStatus;
import com.suppor.rpc.proto.protocol.MsgType;
import com.suppor.rpc.proto.protocol.RpcProtocol;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.reflect.FastClass;

import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentMap;

public class RpcRequestHandler extends SimpleChannelInboundHandler<RpcProtocol<RpcRequest>> {
    private static final Logger LOG = LoggerFactory.getLogger(RpcRequestHandler.class);
    private ConcurrentMap<String, Object> serviceMap;

    public RpcRequestHandler(ConcurrentMap<String, Object> serviceMap) {
        this.serviceMap = serviceMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcProtocol<RpcRequest> rpcRequestRpcProtocol) throws Exception {
        //TODO 这里可以异步处理，IO线程完成读之后，业务可放到业务线程中处理，处理完成后再由IO线程接管，防止IO线程阻塞
        System.out.println("服务端拿到了请求参数: " + new Gson().toJson(rpcRequestRpcProtocol.getHeader()));
        MsgHeader header = rpcRequestRpcProtocol.getHeader();
        // 用来封装响应
        RpcProtocol<RpcResponse> responseRpcProtocol = new RpcProtocol<>();
        header.setMsgType(MsgType.RESPONSE.getType().byteValue());
        responseRpcProtocol.setHeader(header);

        RpcResponse response = new RpcResponse();
        responseRpcProtocol.setBody(response);
        // 服务端调用方法
        try {
            Object result = invokeMethod(rpcRequestRpcProtocol.getBody());
            header.setStatus(MsgStatus.SUCCESS.getCode().byteValue());
            response.setResponse(result);
        } catch (InvocationTargetException e) {
            header.setStatus(MsgStatus.FAIL.getCode().byteValue());
            response.setErrorMsg(e.toString());
            LOG.error("Process Request ServiceName {}, RequestId {}, Error", rpcRequestRpcProtocol.getBody().getServiceImpl(), header.getRequestId());
        }
        channelHandlerContext.writeAndFlush(responseRpcProtocol);
    }

    private Object invokeMethod(RpcRequest request) throws InvocationTargetException {
        String serviceName = RpcServiceUtil.serviceKey(request.getServiceImpl(), request.getServiceVersion());
        Object service = this.serviceMap.get(serviceName);
        if (null != service) {
            // 通过CGLIB的FastClass机制，执行方法
            Class<?> serviceClass = service.getClass();
            String methodName = request.getMethodName();
            Class<?>[] parameterTypes = request.getParameterTypes();
            Object[] parameters = request.getParas();
            FastClass fastClass = FastClass.create(serviceClass);
            int methodIndex = fastClass.getIndex(methodName, parameterTypes);
            Object result = fastClass.invoke(methodIndex, service, parameters);

            return result;
        }
        return null;
    }
}
